/*
 * NCSSParserWrapper.java
 * 
 * Copyright (c) 2007
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.dcarew.javancss.metrics;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.dcarew.javancss.JavaNCSSPlugin;
import org.dcarew.javancss.util.JavaElementVisitor;
import org.eclipse.core.resources.IResource;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.browser.IWebBrowser;
import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
import org.eclipse.ui.dialogs.PropertyPage;

/**
 * 
 * 
 * @author Devon Carew
 */
public class NCSSProjectPropertyPage
	extends PropertyPage
{
	private static final String NCSS_URL = "http://www.kclee.com/clemens/java/javancss/";
	
	private Label	ncssCountText;
	private Label	avgCycCountText;
	private Label	fileCountText;
	private Label	packageCountText;
	private Label	kbCountText;
	
	private boolean	stopStatsCalculation;
	
	
	/**
	 * Create a new NCSSProjectPropertyPage.
	 */
	public NCSSProjectPropertyPage()
	{
		noDefaultAndApplyButton();
		
		setMessage("Java Metrics");
	}
	
	public void dispose()
	{
		stopStatistics();
		
		super.dispose();
	}
	
	protected Control createContents(Composite parent)
	{
		Composite composite = new Composite(parent, SWT.NONE);
		
		GridLayout layout = new GridLayout(1, false);
		layout.marginWidth = 0;
		layout.marginHeight = 0;
		composite.setLayout(layout);
		
		Control simpleStats = createSimpleStats(composite);
		simpleStats.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		
		//createSeparator(composite);
		
		Control ncssStats = createNCSSStats(composite);
		ncssStats.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		
		//createSeparator(composite);
		
		Link link = new Link(composite, SWT.WRAP);
		link.setLayoutData(new GridData(SWT.BEGINNING, SWT.END, true, true));
		link.setText(
			"Non-Commenting Source Statements (NCSS) are an estimate of the actual lines\n" +
			"of Java code. Cyclomatic Complexity Numbers (CCN), or McCabe metrics, are a\n" +
			"measure of code complexity.\n" +
			//"<a href=\"http://en.wikipedia.org/wiki/Cyclomatic_complexity\">Cyclomatic Complexity Numbers</a> (CCN), or McCabe metrics, are a measure of code complexity.\n" +
			"\n" + 
			"Metrics are calculated using the JavaNCSS library. JavaNCSS is copyright Chr.\n" +
			"Clemens Lee and licensed under the GNU General Public License.\n" +
			"<a>" + NCSS_URL + "</a>");
		link.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				openURL(event.text);
			}
		});
		
		// Start the statistics calculation.
		startStatistics();
		
		return composite;
	}
	
	protected Control createSimpleStats(Composite parent)
	{
		Group group = new Group(parent, SWT.NONE);
		group.setText("Java Source Statistics");
		group.setLayout(new GridLayout(2, false));
		
		Label label = new Label(group, SWT.NONE);
		label.setText("Packages:");
		packageCountText = new Label(group, SWT.NONE);
		packageCountText.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
		
		label = new Label(group, SWT.NONE);
		label.setText("Files:");
		fileCountText = new Label(group, SWT.NONE);
		fileCountText.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
		
		label = new Label(group, SWT.NONE);
		label.setText("Total size:");
		kbCountText = new Label(group, SWT.NONE);
		kbCountText.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
		
		return group;
	}
	
	protected Control createNCSSStats(Composite parent)
	{
		Group group = new Group(parent, SWT.NONE);
		group.setText("NCSS and CCN Statistics");
		group.setLayout(new GridLayout(2, false));
		
		Label label = new Label(group, SWT.NONE);
		label.setText("NCSS count:");
		ncssCountText = new Label(group, SWT.NONE);
		ncssCountText.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
		
		label = new Label(group, SWT.NONE);
		label.setText("Average CCN:");
		avgCycCountText = new Label(group, SWT.NONE);
		avgCycCountText.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
		
		return group;
	}
	
	protected Control createSeparator(Composite parent)
	{
		Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
		
		GridData gridData = new GridData();
		gridData.horizontalAlignment = GridData.FILL;
		gridData.grabExcessHorizontalSpace = true;
		separator.setLayoutData(gridData);
		
		return separator;
	}
	
	private void startStatistics()
	{
		stopStatsCalculation = false;
		
		final List resources = getJavaResources();
		
		Runnable statsRunnable = new Runnable() {
			public void run()
			{
				final NCSSMetrics metrics = new NCSSMetrics();
				
				NCSSParserWrapper parser = new NCSSParserWrapper();
				
				for (Iterator itor = resources.iterator(); itor.hasNext() && !stopStatsCalculation;)
				{
					IResource resource = (IResource) itor.next();
					
					parser.parse(resource, metrics);
					
					getControl().getDisplay().syncExec(new Runnable() {
						public void run()
						{
							if (!ncssCountText.isDisposed())
							{
								ncssCountText.setText(metrics.getNcssCountText());
								avgCycCountText.setText(metrics.getAverageCycCountText());
								fileCountText.setText(metrics.getFileCountText());
								packageCountText.setText(metrics.getPackageCountText());
								kbCountText.setText(metrics.getByteCountText());
								
								ncssCountText.getParent().layout();
								ncssCountText.getParent().getParent().layout();
								
								kbCountText.getParent().layout();
								kbCountText.getParent().getParent().layout();
							}
						}
					});
				}
			}
		};
		
		new Thread(statsRunnable).start();
	}
	
	private List getJavaResources()
	{
		try
		{
			if (!(getElement() instanceof IJavaElement))
				return Collections.EMPTY_LIST;
			
			final List resources = new ArrayList();
			
			JavaElementVisitor.accept(new JavaElementVisitor() {
				protected boolean visit(IJavaProject javaProject)
				{
					return javaProject.getProject().getLocation() != null;
				}
				protected boolean visit(IPackageFragmentRoot packageFragmentRoot)
					throws JavaModelException
				{
					return packageFragmentRoot.exists() && !packageFragmentRoot.isArchive()
						&& packageFragmentRoot.getKind() == IPackageFragmentRoot.K_SOURCE;
				}
				protected boolean visit(ICompilationUnit compilationUnit)
				{
					resources.add(compilationUnit.getResource());
					return true;
				}
			}, (IJavaElement)getElement());
			
			return resources;
		}
		catch (JavaModelException exception)
		{
			JavaNCSSPlugin.log(exception);
			
			return Collections.EMPTY_LIST;
		}
	}
	
	private void stopStatistics()
	{
		stopStatsCalculation = true;
	}
	
	/**
	 * Open the given URL in the platform specific default browser.
	 * 
	 * @param url
	 */
	private static void openURL(String url)
	{
		try
		{
			IWorkbenchBrowserSupport browserSupport = PlatformUI.getWorkbench().getBrowserSupport();
			
			IWebBrowser browser = browserSupport.getExternalBrowser();
			
			browser.openURL(new URL(url));
		}
		catch (PartInitException exception)
		{
			JavaNCSSPlugin.log(exception);
		}
		catch (MalformedURLException exception)
		{
			JavaNCSSPlugin.log(exception);
		}
	}
	
}
